home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 722 / 722.xpi / chrome / noscript.jar / content / noscript / Sites.js < prev    next >
Text File  |  2010-02-12  |  10KB  |  358 lines

  1. const SiteUtils = new function() {
  2.   const _domainPattern = this.domainPattern = /^[\w\u0080-\uffff][\w\-\.\u0080-\uffff]*$/;
  3.   this.ios = IOS;  
  4.   this.uriFixup = CC["@mozilla.org/docshell/urifixup;1"].getService(CI.nsIURIFixup);
  5.   
  6.   function sorter(a, b) {
  7.     if (a == b) return 0;
  8.     if (!a) return 1;
  9.     if (!b) return -1;
  10.     const dp = _domainPattern;
  11.     return dp.test(a) ?
  12.         (dp.test(b) ? (a < b ? -1 : 1) : -1)
  13.       : (dp.test(b) ? 1 : a < b ? -1 : 1);
  14.   }
  15.   
  16.   this.sort = function(ss) {
  17.     return ss.sort(sorter);
  18.   };
  19.   
  20.   this.getSite = function(url) {
  21.     if (!url || 
  22.         url.charCodeAt(0) < 33  && // needs trimming
  23.         !(url = url.replace(/^\s*(.*?)\s*$/, '$1'))) {
  24.       return "";
  25.     }
  26.     
  27.     if (url.indexOf(":") == -1) {
  28.       return this.domainMatch(url);
  29.     }
  30.     
  31.     var scheme;
  32.     try {
  33.       scheme = this.ios.extractScheme(url).toLowerCase();
  34.       switch (scheme) {
  35.         case "http": case "https": // commonest case first
  36.           break;
  37.         case "javascript": case "data": 
  38.           return "";
  39.         case "about":
  40.           return url.split(/[\?#]/, 1)[0];
  41.         case "chrome":
  42.           return "chrome:";
  43.       }
  44.       scheme += ":";
  45.       if (url == scheme) return url;
  46.     } catch(ex) {
  47.       return this.domainMatch(url);
  48.     }
  49.     try {
  50.       // let's unwrap JAR uris
  51.       var uri = this.uriFixup.createExposableURI(this.ios.newURI(url, null, null)); // fix wysywyc: and zaps userpass
  52.       if (uri instanceof CI.nsIJARURI) {
  53.         uri = uri.JARFile;
  54.         return uri ? this.getSite(uri.spec) : scheme;
  55.       }
  56.       try  {
  57.         return scheme + "//" + uri.hostPort;
  58.       } catch(exNoHostPort) {
  59.         var host = uri.spec.substring(scheme.length);
  60.         return /^\/\/[^\/]/.test(host) && (host = this.domainMatch(host.replace(/^\/\/([^\/]+).*/, "$1")))
  61.           ? scheme + "//" + host
  62.           : scheme;
  63.       }
  64.     } catch(ex) {
  65.       return "";
  66.     }
  67.   };
  68.   
  69.   this.list2set = function(sl) {
  70.     // kill duplicates
  71.     var prevSite = "";
  72.     var site;
  73.     for (var j = sl.length; j--> 0;) {
  74.       site = sl[j];
  75.       if ((!site) || site == prevSite) { 
  76.         sl.splice(j, 1);
  77.       } else {
  78.         prevSite = site;
  79.       }
  80.     }
  81.     return sl;
  82.   };
  83.   
  84.   this.sortedSet = function(sl) {
  85.     return this.list2set(this.sort(sl));
  86.   }
  87.   
  88.   this.splitString = function(s) {
  89.     return s && /\S/.test(s) && s.split(/\s+/) || [];
  90.   };
  91.   
  92.   this.domainMatch = function(url) {
  93.      const m = url.match(this.domainPattern);
  94.      return m ? m[0].toLowerCase() : "";
  95.   };
  96.   
  97.   this.sanitizeList = function(sl) {
  98.     for (var j = sl.length; j-- > 0; ) {
  99.       sl[j] = this.getSite(sl[j]);
  100.     }
  101.     return sl;
  102.   };
  103.   
  104.   this.sanitizeMap = function(sm) {
  105.     var site;
  106.     delete sm[""];
  107.     for (var url in sm) {
  108.       site = this.getSite(url);
  109.       if (site != url) {
  110.         if (site) sm[site] = sm[url];
  111.         delete sm[url];
  112.       }
  113.     }
  114.     return sm;
  115.   };
  116.   
  117.   this.sanitizeString = function(s) {
  118.     return this.set2string(this.string2set(s)); 
  119.   };
  120.   
  121.   this.string2set = function(s) {
  122.     return this.sortedSet(this.sanitizeList(this.splitString(s)));
  123.   };
  124.   
  125.   this.set2string = function(ss) {
  126.     return ss.join(" ");
  127.   };
  128.   
  129.   this.crop = function(url, width, max) {
  130.     width = width || 100;
  131.     if (url.length < width) return url;
  132.     
  133.     max = max || 2000;
  134.     if (max > width && url.length > max) {
  135.         return this.crop(url.substring(0, max / 2)) + "\n[...]\n" + 
  136.           this.crop(url.substring(url.length - max / 2));
  137.     }
  138.     
  139.     var parts = [];
  140.    
  141.     while (url.length > width) {
  142.       parts.push(url.substring(0, width));
  143.       url = url.substring(width);
  144.     }
  145.     parts.push(url);
  146.     return parts.join("\n");
  147.   };
  148. }
  149.  
  150. function PolicySites(sitesString) {
  151.   if (sitesString) this.sitesString = sitesString;
  152. }
  153. PolicySites.prototype = {
  154.   clone: function() {
  155.     return new PolicySites(this.sitesString);
  156.   }
  157. ,
  158.   equals: function(other) {
  159.     return other && (this.sitesString == other.sitesString);
  160.   }
  161. ,
  162.   _sitesString: "",
  163.   get sitesString() {
  164.     return this._sitesString;
  165.   },
  166.   set sitesString(s) {
  167.     s = SiteUtils.sanitizeString(s);
  168.     if (s != this._sitesString) {
  169.       this._sitesString = s;
  170.       this._sitesMap = null;
  171.       this._sitesList = null;
  172.     }
  173.     return s;
  174.   }
  175. ,
  176.   _sitesList: null,
  177.   get sitesList() {
  178.     return this._sitesList ? this._sitesList : this._sitesList = SiteUtils.splitString(this.sitesString);
  179.   },
  180.   set sitesList(sl) {
  181.     this.sitesString = SiteUtils.set2string(SiteUtils.sortedSet(SiteUtils.sanitizeList(sl)));
  182.     return this.sitesList;
  183.   }
  184. ,
  185.   _sitesMap: null,
  186.   get sitesMap() {
  187.     if (!this._sitesMap) {
  188.       const sm = {};
  189.       const sl = SiteUtils.splitString(this.sitesString);
  190.       if (sl) {
  191.         for (var j = sl.length; j-- > 0;) {
  192.           sm[sl[j]] = true;
  193.         }
  194.       }
  195.       this._sitesMap = sm;
  196.     }
  197.     return this._sitesMap;
  198.   },
  199.   set sitesMap(sm) {
  200.     sm = sm ? SiteUtils.sanitizeMap(sm) : {};
  201.     var sl = [];
  202.     for (var s in sm) {
  203.       sl.push(s);
  204.     }
  205.     
  206.     this._sitesString = SiteUtils.set2string(SiteUtils.sort(sl));
  207.     this._sitesList = null;
  208.     return this._sitesMap = sm;
  209.   }
  210. ,
  211.   fromPref: function(pref, name) {
  212.     if (!this.settingPref) {
  213.       try {
  214.         this.sitesString = pref.getCharPref(name || "sites")
  215.           .replace(/[^\u0000-\u007f]+/g, function($0) { return decodeURIComponent(escape($0)) });
  216.       } catch(e) {
  217.         this.siteString = "";
  218.         return false;
  219.       }
  220.     }
  221.     return true;
  222.   }
  223. ,
  224.   settingPref: false,
  225.   toPref: function(pref, name) {
  226.     if (!name) name = "sites";
  227.     if (pref.prefIsLocked(name)) {
  228.       this.fromPref(pref);
  229.       return;
  230.     }
  231.     var change;
  232.     var s = this.sitesString.replace(/[^\u0000-\u007f]+/g,function($0) { return unescape(encodeURIComponent($0)) });
  233.     try {
  234.       change = s != pref.getCharPref(name);
  235.     } catch(ex) {
  236.       change = true;
  237.     }
  238.     
  239.     if (change) {
  240.       this.settingPref = true;
  241.       try {
  242.         pref.setCharPref(name, s);
  243.       } finally {
  244.         this.settingPref = false;
  245.       }
  246.     }
  247.   }
  248. ,
  249.   // returns the shortest match for a site, or "" if no match is found
  250.   matches: function(site) {
  251.     if (!site) return "";
  252.     const sm = this.sitesMap;
  253.     var match;
  254.     var dots; // track "dots" for fix to 2nd level domain policy lookup flaw 
  255.     var pos = site.indexOf(':') + 1;
  256.     if (pos > 0 && (pos == site.length || site[pos] == '/')) {
  257.       if (sm[match = site.substring(0, pos)]) return match; // scheme match
  258.       if (++pos >= site.length || site[pos] != '/') return "";
  259.       match = site.substring(pos + 1);
  260.       dots = 0;
  261.     } else {
  262.       match = site;
  263.       dots = 1;
  264.     }
  265.  
  266.     var submatch;
  267.     for (pos = match.lastIndexOf('.'); pos > 0; dots++) {
  268.       pos = match.lastIndexOf('.', pos - 1);
  269.       if ((dots || pos > -1) && sm[submatch = match.substring(pos + 1)]) {
  270.         return submatch; // domain/subdomain match
  271.       }
  272.     }
  273.     
  274.     if (sm[match]
  275.         && (dots > 1 || sm[site]) // strict CAPS-style matching
  276.         ) return match; // host match
  277.     return sm[site] ? site : ""; // full match
  278.   }
  279. ,
  280.  
  281.  
  282.   _remove: function(site) {
  283.     const sm = this.sitesMap;
  284.     delete sm[site];
  285.     if (site.indexOf(":") < 0 && site.indexOf(".") == site.lastIndexOf(".")) {
  286.       // base domain hack
  287.       delete sm["http://" + site];
  288.       delete sm["https://" + site];
  289.       delete sm["file://" + site];
  290.       delete sm["ftp://" + site];
  291.     }
  292.   },
  293.   remove: function(sites, keepUp, keepDown) {
  294.     if (!sites) return false;
  295.     if (!(typeof(sites) == "object" && "push" in sites)) 
  296.       return this.remove([sites], keepUp, keepDown);
  297.     keepUp = keepUp || false;
  298.     keepDown = keepDown || false;
  299.     
  300.     const sm = this.sitesMap;
  301.     var change = false;
  302.     var site, match;
  303.     var tmp= keepDown ? null : new PolicySites();
  304.     for (var j = sites.length; j-- > 0;) {
  305.       site = sites[j];
  306.       if (site[site.length-1] != ":") { // not a scheme only site
  307.         if (!keepUp) {
  308.           while ((match = this.matches(site)) && site != match) { // remove ancestors
  309.             this._remove(match);
  310.             change = true;
  311.           }
  312.         }
  313.         if (!keepDown) {
  314.           tmp.sitesString = site;
  315.           for (match in sm) { // remove descendants
  316.             if (tmp.matches(match)) {
  317.               if (site != match) delete sm[match];
  318.               change = true;
  319.             }
  320.           }
  321.           this._remove(site);
  322.         }
  323.       }
  324.     
  325.       if (site in sm) {
  326.         this._remove(site);
  327.         change = true;
  328.       }
  329.     }
  330.     if (change) this.sitesMap = this._sitesMap;
  331.     return change;
  332.   },
  333.   
  334.   _add: function(site) {
  335.     return (site in this.sitesMap ? false : this.sitesMap[site] = true);
  336.   },
  337.   
  338.   add: function(sites) {
  339.     if (!sites) return false;
  340.     if (!(typeof(sites) == "object" && "push" in sites)) 
  341.       return this.add([sites]);
  342.     
  343.     var change = false;
  344.     var site;
  345.     for (var j = sites.length; j-- > 0;) {
  346.       site = sites[j];
  347.       if (site.indexOf(":") < 0 && site.indexOf(".") == site.lastIndexOf(".")) {
  348.         // base domain hack
  349.         if(this._add("http://" + site)) change = true;
  350.         if(this._add("https://" + site)) change = true;
  351.       }
  352.       if (this._add(site)) change = true;
  353.     }
  354.     if (change) this.sitesMap = this._sitesMap;
  355.     return change;
  356.   }
  357. };
  358.